﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Game.Model
{
    /// <summary>
    /// 角色模型
    /// </summary>
    public class Character
    {
        /// <summary>
        /// 实例 Id
        /// </summary>
        private int _Id;
        
        /// <summary>
        /// 模板数据 Id
        /// </summary>
        private short _DataId;

        /// <summary>
        /// 能力值
        /// </summary>
        private sbyte[] _Ability;

        /// <summary>
        /// 技能熟练度表
        /// K: 技能模板数据 Id
        /// V: 对应的(等级, 经验)值
        /// </summary>
        private IDictionary<short, (sbyte Level, sbyte Exp)> _SkillExps;

        /// <summary>
        /// Hp 数值
        /// </summary>
        private int _Hp;

        /// <summary>
        /// 构造
        /// </summary>
        public Character(int id, short dataId)
        {
            var data = Data.Character.Data[dataId];
            _Id = id;
            _DataId = dataId;
            {
                // 根据配置数据初始化自身能力值
                _Ability = new sbyte[Data.Ability.Data.Count];
                _Ability[Data.Ability.ExportId.Str] = data.Pow;
                _Ability[Data.Ability.ExportId.Agi] = data.Agi;
                _Ability[Data.Ability.ExportId.Con] = data.Phs;
                _Ability[Data.Ability.ExportId.Int] = data.Int;
                _Ability[Data.Ability.ExportId.Mag] = data.Mgc;
                _Ability[Data.Ability.ExportId.Luc] = data.Luk;
            }
            {
                _SkillExps = new Dictionary<short, (sbyte Level, sbyte Exp)>();
                // 根据技能数据表初始化角色共通的技能表
                for (int i = 0, len = Data.Skill.Data.Count; i < len; i++)
                {
                    var skillData = Data.Skill.Data[i];
                    // 只获得初始习得的技能
                    if (skillData.IsLearned)
                    {
                        _SkillExps.Add(skillData.Id, (skillData.Level, skillData.EXP));
                    }
                }
                // 根据角色数据初始化自身的自带技能表
                if (data.Skills != null)
                    foreach (var (skillId, exp, level) in data.Skills)
                    {
                        _SkillExps[skillId] = (level, exp);
                    }
            }
            {
                // 数值修正
                RecoverHp();
            }
        }

        /// <summary>
        /// 实例 Id
        /// </summary>
        public int Id => _Id;

        /// <summary>
        /// 模板数据 Id
        /// </summary>
        public short DataId => _DataId;

        #region AbilityAccess

        /// <summary>
        /// 获取能力值
        /// </summary>
        public int GetAgility(sbyte index) => Math.Max((sbyte) 1, Math.Min(_Ability[index], sbyte.MaxValue));
        
        /// <summary>
        /// 设置能力值
        /// </summary>
        public void SetAgility(sbyte index, int value) => _Ability[index] = (sbyte) Math.Max(sbyte.MinValue, Math.Min(value, sbyte.MaxValue));

        /// <summary>
        /// 力量
        /// </summary>
        public int Str
        {
            get => GetAgility(Data.Ability.ExportId.Str);
            set => SetAgility(Data.Ability.ExportId.Str, value);
        }
        
        /// <summary>
        /// 敏捷
        /// </summary>
        public int Agi
        {
            get => GetAgility(Data.Ability.ExportId.Agi);
            set => SetAgility(Data.Ability.ExportId.Agi, value);
        }
        
        /// <summary>
        /// 体质
        /// </summary>
        public int Con
        {
            get => GetAgility(Data.Ability.ExportId.Con);
            set => SetAgility(Data.Ability.ExportId.Con, value);
        }
        
        /// <summary>
        /// 智力
        /// </summary>
        public int Int
        {
            get => GetAgility(Data.Ability.ExportId.Int);
            set => SetAgility(Data.Ability.ExportId.Int, value);
        }

        /// <summary>
        /// 幸运
        /// </summary>
        public int Luc
        {
            get => GetAgility(Data.Ability.ExportId.Luc);
            set => SetAgility(Data.Ability.ExportId.Luc, value);
        }

        /// <summary>
        /// 魔力
        /// </summary>
        public int Mag
        {
            get => GetAgility(Data.Ability.ExportId.Mag);
            set => SetAgility(Data.Ability.ExportId.Mag, value);
        }
        
        #endregion

        #region SkillAccess

        /// <summary>
        /// 获取技能表
        /// </summary>
        public short[] GetSkillList() => _SkillExps.Keys.ToArray();

        /// <summary>
        /// 获取技能等级(熟练度)
        /// </summary>
        public sbyte GetSkillLevel(short skillId)
        {
            if (_SkillExps.TryGetValue(skillId, out var tuple))
            {
                return tuple.Level;
            }
            return -1;
        }

        #endregion
        
        #region CacheAccess

        /// <summary>
        /// Hp 上限
        /// </summary>
        public int MaxHp => Math.Max(1, Con);

        /// <summary>
        /// Hp
        /// </summary>
        public int Hp
        {
            get => Math.Max(0, Math.Min(_Hp, MaxHp));
            set => _Hp = value;
        }

        /// <summary>
        /// 回复 Hp
        /// </summary>
        public void RecoverHp()
        {
            Hp = MaxHp;
        }

        /// <summary>
        /// 是否应是战败单位
        /// </summary>
        public bool IsShouldDefeated => Hp <= 0;

        /// <summary>
        /// 命中率
        /// </summary>
        public float Hit => 1.0f * (Agi / sbyte.MaxValue) + 0.3f * (Luc / sbyte.MaxValue);

        /// <summary>
        /// 闪避率
        /// </summary>
        public float Avd => 0.75f * (Agi / sbyte.MaxValue) + 0.25f * (Luc / sbyte.MaxValue);

        /// <summary>
        /// 基础移动力
        /// </summary>
        public int BaseMovePoint => Agi / 12;

        /// <summary>
        /// 移动力
        /// </summary>
        public int MovePoint => Math.Max(1, BaseMovePoint + 0);

        /// <summary>
        /// 地位等级
        /// </summary>
        public int ClassLevel
        {
            get
            {
                var result = 0;
                var abilitySum = 0;
                for (var i = 0; i < _Ability.Length; i++)
                {
                    abilitySum += _Ability[i];
                }
                result += (abilitySum / _Ability.Length) / 10;
                result += IsUnique ? 2 : -1;
                return Math.Max(1, result);
            }
        }

        #endregion

        #region TemplateAccess

        /// <summary>
        /// 获取模板数据
        /// </summary>
        public Data.Character GetTemplateData() => Data.Character.Data[_DataId];

        /// <summary>
        /// 是否唯一角色
        /// </summary>
        public bool IsUnique => GetTemplateData().AmountLimit.Max == 1;
        
        /// <summary>
        /// 姓名
        /// </summary>
        public string Name
        {
            get
            {
                if (IsUnique)
                    return GetTemplateData().Name;
                else
                    return $"{GetTemplateData().Name} {_Id} 号";
            }
        }

        /// <summary>
        /// 描述
        /// </summary>
        public string Desc
        {
            get
            {
                if (IsUnique)
                    return GetTemplateData().Desc;
                else
                    return string.Format(GetTemplateData().Desc, _Id);
            }
        }

        /// <summary>
        /// 性别
        /// </summary>
        public sbyte SexType => GetTemplateData().Sex;

        #endregion
    }
}